#include "mqprotocolconfig.h"
#include <QJsonDocument>
#include <QJsonParseError>
#include <QFile>
#include <QDebug>
#include <QDir>
#include <QApplication>

/**
 * @brief 构造函数
 */
MQProtocolConfig::MQProtocolConfig()
{
}

/**
 * @brief 加载配置文件
 * @param configPath 配置文件路径，默认为"mq_protocol_config.json"
 * @return 加载成功返回true，失败返回false
 */
bool MQProtocolConfig::loadConfig(const QString& configPath)
{
    // 构建完整的配置文件路径
    m_configFilePath = QApplication::applicationDirPath() + "/" + configPath;

    qDebug()<<m_configFilePath;

    QFile file(m_configFilePath);
    if (!file.open(QIODevice::ReadOnly)) {
        qDebug() << "Failed to open protocol config file:" << m_configFilePath;
        return false;
    }
    
    QByteArray data = file.readAll();
    file.close();
    
    QJsonParseError error;
    QJsonDocument doc = QJsonDocument::fromJson(data, &error);
    
    if (error.error != QJsonParseError::NoError) {
        qDebug() << "Failed to parse protocol config JSON:" << error.errorString();
        qDebug() << "Error at offset:" << error.offset;
        return false;
    }
    
    m_protocolConfig = doc.object();
    qDebug() << "Protocol config loaded successfully from:" << m_configFilePath;
    qDebug() << "Loaded protocols:" << m_protocolConfig.keys();
    
    return true;
}

/**
 * @brief 获取指定function_code的字段结构
 * @param functionCode 功能代码
 * @return 返回包含字段结构的QJsonObject
 */
QJsonObject MQProtocolConfig::getProtocolFields(const QString& functionCode) const
{
    if (m_protocolConfig.contains(functionCode)) {
        return m_protocolConfig[functionCode].toObject();
    }
    
    qDebug() << "Protocol not found for function_code:" << functionCode;
    return QJsonObject();
}

/**
 * @brief 检查指定function_code是否存在配置
 * @param functionCode 功能代码
 * @return 存在返回true，不存在返回false
 */
bool MQProtocolConfig::hasProtocol(const QString& functionCode) const
{
    return m_protocolConfig.contains(functionCode);
}

/**
 * @brief 获取指定字段的必需字段列表（只返回字段名）
 * @param functionCode 功能代码
 * @param fieldName 字段名
 * @return 返回字段名列表
 */
QStringList MQProtocolConfig::getRequiredFields(const QString& functionCode, const QString& fieldName) const
{
    QJsonObject protocolFields = getProtocolFields(functionCode);
    if (protocolFields.contains(fieldName)) {
        QJsonValue fieldValue = protocolFields[fieldName];
        
        // 如果是数组格式（旧格式兼容）
        if (fieldValue.isArray()) {
            QJsonArray fieldsArray = fieldValue.toArray();
            QStringList fieldsList;
            for (const QJsonValue& value : fieldsArray) {
                fieldsList.append(value.toString());
            }
            return fieldsList;
        }
        // 如果是对象格式（新格式，包含类型信息）
        else if (fieldValue.isObject()) {
            QJsonObject fieldsObject = fieldValue.toObject();
            return fieldsObject.keys();
        }
    }
    
    qDebug() << "Field not found:" << fieldName << "for function_code:" << functionCode;
    return QStringList();
}

/**
 * @brief 获取指定字段的字段信息（包含类型）
 * @param functionCode 功能代码
 * @param fieldName 字段名
 * @return 返回字段信息列表
 */
QList<FieldInfo> MQProtocolConfig::getFieldInfos(const QString& functionCode, const QString& fieldName) const
{
    QList<FieldInfo> fieldInfos;
    QJsonObject protocolFields = getProtocolFields(functionCode);
    
    if (protocolFields.contains(fieldName)) {
        QJsonValue fieldValue = protocolFields[fieldName];
        
        // 如果是对象格式（包含类型信息）
        if (fieldValue.isObject()) {
            QJsonObject fieldsObject = fieldValue.toObject();
            
            for (auto it = fieldsObject.begin(); it != fieldsObject.end(); ++it) {
                FieldInfo info;
                info.name = it.key();
                info.type = it.value().toString();
                fieldInfos.append(info);
            }
        }
        // 如果是数组格式（旧格式兼容，类型默认为string）
        else if (fieldValue.isArray()) {
            QJsonArray fieldsArray = fieldValue.toArray();
            for (const QJsonValue& value : fieldsArray) {
                FieldInfo info;
                info.name = value.toString();
                info.type = "string";  // 默认类型
                fieldInfos.append(info);
            }
        }
    }
    
    return fieldInfos;
}

/**
 * @brief 获取指定字段的类型
 * @param functionCode 功能代码
 * @param fieldName 字段名
 * @param subFieldName 子字段名
 * @return 返回字段类型字符串
 */
QString MQProtocolConfig::getFieldType(const QString& functionCode, const QString& fieldName, const QString& subFieldName) const
{
    QJsonObject protocolFields = getProtocolFields(functionCode);
    if (protocolFields.contains(fieldName)) {
        QJsonValue fieldValue = protocolFields[fieldName];
        
        if (fieldValue.isObject()) {
            QJsonObject fieldsObject = fieldValue.toObject();
            if (fieldsObject.contains(subFieldName)) {
                return fieldsObject[subFieldName].toString();
            }
        }
    }
    
    qDebug() << "Field type not found:" << fieldName << "." << subFieldName << "for function_code:" << functionCode;
    return QString();
}

/**
 * @brief 重新加载配置文件
 * @return 重新加载成功返回true，失败返回false
 */
bool MQProtocolConfig::reloadConfig()
{
    if (m_configFilePath.isEmpty()) {
        qDebug() << "No config file path set, cannot reload";
        return false;
    }
    
    // 清空当前配置
    m_protocolConfig = QJsonObject();
    
    // 重新加载
    QFile file(m_configFilePath);
    if (!file.open(QIODevice::ReadOnly)) {
        qDebug() << "Failed to reopen protocol config file:" << m_configFilePath;
        return false;
    }
    
    QByteArray data = file.readAll();
    file.close();
    
    QJsonParseError error;
    QJsonDocument doc = QJsonDocument::fromJson(data, &error);
    
    if (error.error != QJsonParseError::NoError) {
        qDebug() << "Failed to reparse protocol config JSON:" << error.errorString();
        return false;
    }
    
    m_protocolConfig = doc.object();
    qDebug() << "Protocol config reloaded successfully";
    
    return true;
}

/**
 * @brief 获取当前配置文件路径
 * @return 返回配置文件完整路径
 */
QString MQProtocolConfig::getConfigPath() const
{
    return m_configFilePath;
}
